﻿using GetThis_Server.Options;
using GetThis_Server.Users;
using Server;
using System;
using System.Diagnostics.Contracts;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace GetThis_Server
{
    public partial class MDIMain : Form
    {
        #region Fields

        private readonly ApplicationParameters m_applicationParameters = new ApplicationParameters();

        private readonly Data m_data = new Data();

        private readonly ServerManager m_serverManager;

        #endregion

        #region Constructors

        public MDIMain()
        {
            InitializeComponent();
            if (!m_applicationParameters.TryLoad(Log)) LogAndClose("Erreur lors du chargement des paramètres...");
            if (!m_data.TryLoad(m_applicationParameters.DataPath)) LogAndClose("Erreur lors du chargement des données...");
            m_applicationParameters.ServerParameters = tcpServer.ServerParameters;
            m_applicationParameters.ServerParameters.Encoding = Encoding.UTF8;
            m_serverManager = new ServerManager(tcpServer, m_data, InvokeLog, InvokeStopServer);
            startMenuItem.PerformClick();
        }

        #endregion

        #region Properties

        internal TcpServer TcpServer
        {
            get
            {
                Contract.Ensures(Contract.Result<TcpServer>() != null);

                return tcpServer;
            }
        }

        #endregion

        #region Events

        private void startMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                startMenuItem.Enabled = optionsMenu.Enabled = false;
                stopMenuItem.Enabled = true;
                tcpServer.Start();
                Log(String.Format("Nouvelles connections en écoute sur le port {0}", tcpServer.ServerParameters.ConnectionPort));
                Log(String.Format("Serveur en écoute sur le port {0}", tcpServer.ServerParameters.ServerPort));
            }
            catch (SystemException ex)
            {
                Log(String.Format("Erreur lors du démarrage du serveur (erreur : {0})", ex.Message));
                StopServer();
            }
        }

        private void stopMenuItem_Click(object sender, EventArgs e)
        {
            StopServer();
        }

        private void optionsMenu_Click(object sender, EventArgs e)
        {
            new OptionsForm(m_applicationParameters, m_data, Log).ShowDialog();
        }

        private void usersMenu_Click(object sender, EventArgs e)
        {
            new UsersForm(m_applicationParameters.DataPath, m_data, Log).ShowDialog();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Define the invariant valid state for this class.
        /// </summary>
        [ContractInvariantMethod]
        private void InvariantValidState()
        {
            Contract.Invariant(m_applicationParameters != null);
            Contract.Invariant(m_serverManager != null);
            Contract.Invariant(m_data != null);
            Contract.Invariant(txtLogs != null);
            Contract.Invariant(tcpServer != null);
            Contract.Invariant(startMenuItem != null);
            Contract.Invariant(stopMenuItem != null);
            Contract.Invariant(usersMenu != null);
            Contract.Invariant(optionsMenu != null);
        }

        private void LogAndClose(string text)
        {
            Log(text);
            Thread.Sleep(5000);
            Close();
        }

        private void Log(string text)
        {
            txtLogs.Text += String.Format("{0} - {1}\r\n", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss tt"), text);
            if (txtLogs.Lines != null && txtLogs.Lines.Length > 500)
            {
                string[] temp = new string[500];
                Array.Copy(txtLogs.Lines, txtLogs.Lines.Length - 500, temp, 0, 500);
                txtLogs.Lines = temp;
            }
            Contract.Assume(txtLogs.Text != null);
            txtLogs.SelectionStart = txtLogs.Text.Length;
            txtLogs.ScrollToCaret();
        }

        private void StopServer()
        {
            try
            {
                tcpServer.Stop();
                Log("Serveur arrêté");
            }
            catch (SystemException e)
            {
                Log(String.Format("Erreur pendant l'arrêt du serveur : {0}", e.Message));
            }
            finally
            {
                stopMenuItem.Enabled = false;
                startMenuItem.Enabled = optionsMenu.Enabled = true;
            }
        }

        private void InvokeLog(string text)
        {
            Invoke((MethodInvoker)(() => Log(text)));
        }

        private void InvokeStopServer()
        {
            Invoke((MethodInvoker)(() => StopServer()));
        }

        #endregion

    }
}
